This analysis revolves around the undergraduate thesis carried out by Franco Sebastián Benítez, under the supervision of Débora Burin and Lucas Cuenya, from the School of Psychology of the University of Buenos Aires. The same was performed by the first author.
As set in our preregistration, we are checking the following aspects:
1) Check for exclusion criteria in the demographic data, and in the completion rate.
2) Describe the sample’s demographic characteristics.
3) Analyse the total percentage of “yes” responses to belief in crisis. Analyse as a function of career stage and methodological approach.
4) Qualitative analysis of open field response to belief in crisis.
5) Percentage of agreement with each, and combined, statements about replication crisis, p-value, publication bias. Analyse as a function of career stage and methodological approach.
6) Percentage of agreement with each, and combined, statements about perceived barriers. Analyse as a function of career stage and methodological approach.
7) Percentage of agreement with each, and combined, statements about attitudes against adopting open science practices. Analyse as a function of career stage and methodological approach.
8) Qualitative analysis of open field response to attitudes about barriers against adopting open science practices.
Let's set all plots in the middle of the notebook.
from IPython.core.display import HTML
HTML("""
<style>
.output_png {
display: table-cell;
text-align: center;
vertical-align: middle;
}
</style>
""")
import pandas as pd # data wrangling
import matplotlib.pyplot as plt # plotting
import seaborn as sns # plotting 2.0
import re # format text
from wordcloud import WordCloud, STOPWORDS # text analysis
from unidecode import unidecode # remove accents
import numpy as np # numerical manipulations
df = pd.read_csv("../data/Percepciones sobre ciencia y ciencia abierta.csv")
pd.set_option('max_columns', None) # display all columns
pd.set_option('display.max_colwidth', None) # display full column information
Let's look at the first five cases.
df.head()
df.shape
The data contains 95 rows and 53 columns.
Let's rename the columns to make it easier to manipulate and plot.
column_names = {"Timestamp": "timestamp",
"¿Acepta participar?": "consent",
"Edad (años)": "age",
"Nivel educativo alcanzado": "education",
"Área/s de investigación": "area",
"¿Ha participado en un proyecto de investigación (v. g., UBACyT, CONICET) en los últimos 5 años?": "project",
"¿Ha publicado en una revista indexada con referato (v. g., Scopus, Scimago, Scielo) en los últimos 5 años?": "journal",
"Marque su posición actual en la Facultad de Psicología de la UBA": "position",
"¿Qué tipo de metodología suele predominar en sus estudios?": "methodology",
"¿Cree que hay una crisis en la ciencia?": "belief",
"Si su respuesta a la pregunta anterior ha sido “Sí”, señale por qué cree que hay una crisis en la ciencia": "belief_comments",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Gran parte de los investigadores solamente publica los estudios en donde obtienen diferencias estadísticamente significativas]": "Gran parte de los investigadores solamente publica los estudios en donde obtienen diferencias estadísticamente significativas",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [A las revistas científicas no les interesa publicar resultados que no son estadísticamente significativos]": "A las revistas científicas no les interesa publicar resultados que no son estadísticamente significativos",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Cuando leo un artículo tengo mayor confianza en la calidad del estudio si los resultados son estadísticamente significativos]": "Cuando leo un artículo tengo mayor confianza en la calidad del estudio si los resultados son estadísticamente significativos",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Que un resultado no fuera estadísticamente significativo sería un criterio para no seguir investigando esas variables]": "Que un resultado no fuera estadísticamente significativo sería un criterio para no seguir investigando esas variables",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Una conclusión científica (por ejemplo, si un tratamiento es mejor que otro) debe estar basado en si el p-valor es o no es estadísticamente significativo]": "Una conclusión científica (por ejemplo, si un tratamiento es mejor que otro) debe estar basado en si el p-valor es o no es estadísticamente significativo",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Un resultado estadísticamente significativo es un resultado importante]": "Un resultado estadísticamente significativo es un resultado importante",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [El valor de p < .05 confirma que el hallazgo será útil para la comunidad científica]": "El valor de p < .05 confirma que el hallazgo será útil para la comunidad científica",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [El valor de p = .001 confirma que el tamaño del efecto ha sido grande]": "El valor de p = .001 confirma que el tamaño del efecto ha sido grande",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática]": "Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [La realización de estudios de replicación es necesaria para el avance de la ciencia]": "La realización de estudios de replicación es necesaria para el avance de la ciencia",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Si los resultados sobre una determinada temática son unánimes por parte de diferentes equipos de investigación entonces los estudios de replicación no son necesarios]": "Si los resultados sobre una determinada temática son unánimes por parte de diferentes equipos de investigación entonces los estudios de replicación no son necesarios",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Los estudios de replicación solamente tienen sentido cuando no se detectan diferencias estadísticamente significativas en el estudio original]": "Los estudios de replicación solamente tienen sentido cuando no se detectan diferencias estadísticamente significativas en el estudio original",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [No es necesario replicar un estudio cuando ya se detectaron efectos estadísticamente significativos en el estudio original]": "No es necesario replicar un estudio cuando ya se detectaron efectos estadísticamente significativos en el estudio original",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [El principal objetivo de las revistas científicas es publicar hallazgos novedosos]": "El principal objetivo de las revistas científicas es publicar hallazgos novedosos",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [La ciencia avanza más con estudios que plantean hipótesis novedosas que con estudios de replicación de otras investigaciones]": "La ciencia avanza más con estudios que plantean hipótesis novedosas que con estudios de replicación de otras investigaciones",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Creo que, en general, los errores que se pueden haber cometido en un estudio científico siempre se detectan y corrigen antes de ser publicados]": "Creo que, en general, los errores que se pueden haber cometido en un estudio científico siempre se detectan y corrigen antes de ser publicados",
"Valore cada una de las siguientes cuestiones relacionadas con su opinión sobre la ciencia [Las tareas de revisión y corrección de los manuscritos que llevan a cabo los revisores de las revistas garantizan de forma fiable la calidad de los resultados científicos]": "Las tareas de revisión y corrección de los manuscritos que llevan a cabo los revisores de las revistas garantizan de forma fiable la calidad de los resultados científicos",
" [Replicar un estudio previo]": "Replicar un estudio previo (1)",
" [Pre-registrar un estudio antes de iniciar la recolección de datos]": "Pre-registrar un estudio antes de iniciar la recolección de datos (1)",
" [Poner datos recolectados a disposición mediante plataformas o repositorios públicos.]": "Poner datos recolectados a disposición mediante plataformas o repositorios públicos (1)",
" [Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos]": "Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (1)",
" [Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos]": "Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (1)",
" [Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio]": "Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (1)",
" [Compartir una pre-impresión (pre-print) publicándola en un repositorio público o semi-público]": "Compartir una pre-impresión (pre-print) publicándola en un repositorio público o semi-público (1)",
" [Usar revisión por pares abierta]": "Usar revisión por pares abierta (1)",
" [Publicar en revistas de acceso abierto]": "Publicar en revistas de acceso abierto (1)",
" [Adaptar un test psicométrico]": "Adaptar un test psicométrico (1)",
" [Participar en proyectos abiertos y colaborativos a gran escala]": "Participar en proyectos abiertos y colaborativos a gran escala (1)",
" [Replicar un estudio previo].1": "Replicar un estudio previo (2)",
" [Pre-registrar un estudio antes de iniciar la recolección de datos].1": "Pre-registrar un estudio antes de iniciar la recolección de datos (2)",
" [Poner datos recolectados a disposición mediante plataformas o repositorios públicos]": "Poner datos recolectados a disposición mediante plataformas o repositorios públicos (2)",
" [Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos].1": "Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (2)",
" [Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos].1": "Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (2)",
" [Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio].1": "Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (2)",
" [Compartir una pre-impresión (pre-print) publicándola en un repositorio de confianza]": "Compartir una pre-impresión (pre-print) publicándola en un repositorio de confianza (2)",
" [Usar revisión por partes abierta]": "Usar revisión por partes abierta (2)",
" [Publicar en revistas de acceso abierto].1": "Publicar en revistas de acceso abierto (2)",
" [Adaptar un test psicométrico].1": "Adaptar un test psicométrico (2)",
" [Participar en proyectos abiertos y colaborativos a gran escala].1": "Participar en proyectos abiertos y colaborativos a gran escala (2)",
"¿Cuáles le parecen que son las mayores barreras para la aceptación y puesta en práctica de prácticas de ciencia abierta en su campo y/o lugar de trabajo?": "barriers_1",
"Si aplica, por favor describa brevemente qué barreras ha experimentado para incorporar o mantener prácticas de ciencia abierta": "barriers_2",
"Por último, si posee alguna idea o comentario respecto a esta encuesta o al tema que aborda, por favor escribalo brevemente a continuación ": "comments"
}
df.rename(columns = column_names, inplace=True)
df.timestamp = pd.to_datetime(df.timestamp)
df.age = [re.sub(r"[a-zñ]+", "", i) for i in df["age"]] # remove " años" in values, to convert them in integers
df.age = pd.to_numeric(df.age, downcast="integer")
Let's check all the types.
df.dtypes
Most of them are of type "object".
Let's check all the renamings.
df.columns
To be considered "researchers", our respondents should either have participated in a research project or have publicated in a scientific journal. In both cases, in a maximum range of five years.
exclusion_criteria = df[["project", "journal"]]
excluded = []
for (i, (a, b)) in enumerate(exclusion_criteria.itertuples(index=False), start=0):
if a == "No" and b == "No":
print(f"Participant n° {i} will be excluded")
excluded.append(i)
df = df.drop(excluded, axis=0)
df.shape
Now we have five participants (rows) less.
Let's see the data.
df["education"]
We plot the data directly, creating a function we will reuse later.
def horizontal_bar_plot(serie, title=None):
y = serie.value_counts(ascending=True)
fig, ax = plt.subplots(figsize=(20,15))
ax.tick_params(labelsize=20)
ax.barh(y.index, y, height=0.75)
ax.set_title(title, fontsize=20)
ax.set_xlabel("Researchers", fontsize=20)
ax.set_ylabel("Frecuency", fontsize=20)
_, xmax = plt.xlim()
plt.xlim(0, xmax)
for i, v in enumerate(y):
ax.text(v + .5, i, str(v), fontsize=20, ha='left', va='center')
plt.show()
horizontal_bar_plot(df["education"], "Education")
Let's go to clean the data a little. We will group each category into four large groups: "Doctorado", "Licenciatura", "Especialización", and "Maestría", regardless of whether it is ongoing or completed. In addition, since we only have one "Postdoctorado", the same will be located in "Doctorado".
First, let's go to separate our different categories by semicolon. For that, we create a new dataframe specific to our variable. The same contains more rows because of the previous rows were expanded by semicolon. The variable, in this case, will be called "education_df".
Note: We add the "belief" variable because we will use this variable later.
education_df = df[["education",
"belief",
'Gran parte de los investigadores solamente publica los estudios en donde obtienen diferencias estadísticamente significativas',
'A las revistas científicas no les interesa publicar resultados que no son estadísticamente significativos',
'Cuando leo un artículo tengo mayor confianza en la calidad del estudio si los resultados son estadísticamente significativos',
'Que un resultado no fuera estadísticamente significativo sería un criterio para no seguir investigando esas variables',
'Una conclusión científica (por ejemplo, si un tratamiento es mejor que otro) debe estar basado en si el p-valor es o no es estadísticamente significativo',
'Un resultado estadísticamente significativo es un resultado importante',
'El valor de p < .05 confirma que el hallazgo será útil para la comunidad científica',
'El valor de p = .001 confirma que el tamaño del efecto ha sido grande',
'Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática',
'La realización de estudios de replicación es necesaria para el avance de la ciencia',
'Si los resultados sobre una determinada temática son unánimes por parte de diferentes equipos de investigación entonces los estudios de replicación no son necesarios',
'Los estudios de replicación solamente tienen sentido cuando no se detectan diferencias estadísticamente significativas en el estudio original',
'No es necesario replicar un estudio cuando ya se detectaron efectos estadísticamente significativos en el estudio original',
'El principal objetivo de las revistas científicas es publicar hallazgos novedosos',
'La ciencia avanza más con estudios que plantean hipótesis novedosas que con estudios de replicación de otras investigaciones',
'Creo que, en general, los errores que se pueden haber cometido en un estudio científico siempre se detectan y corrigen antes de ser publicados',
'Las tareas de revisión y corrección de los manuscritos que llevan a cabo los revisores de las revistas garantizan de forma fiable la calidad de los resultados científicos',
'Replicar un estudio previo (1)',
'Pre-registrar un estudio antes de iniciar la recolección de datos (1)',
'Poner datos recolectados a disposición mediante plataformas o repositorios públicos (1)',
'Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (1)',
'Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (1)',
'Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (1)',
'Compartir una pre-impresión (pre-print) publicándola en un repositorio público o semi-público (1)',
'Usar revisión por pares abierta (1)',
'Publicar en revistas de acceso abierto (1)',
'Adaptar un test psicométrico (1)',
'Participar en proyectos abiertos y colaborativos a gran escala (1)',
'Replicar un estudio previo (2)',
'Pre-registrar un estudio antes de iniciar la recolección de datos (2)',
'Poner datos recolectados a disposición mediante plataformas o repositorios públicos (2)',
'Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (2)',
'Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (2)',
'Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (2)',
'Compartir una pre-impresión (pre-print) publicándola en un repositorio de confianza (2)',
'Usar revisión por partes abierta (2)',
'Publicar en revistas de acceso abierto (2)',
'Adaptar un test psicométrico (2)',
'Participar en proyectos abiertos y colaborativos a gran escala (2)'
]].assign(education=df["education"].str.split(";")).explode("education").reset_index(drop=True)
We have the next new dataframe:
education_df
Let's replace creating a new function we will use later.
def replace_columns(df, column_to_replace, original, replaced):
"""
Returns: a df and its columns with strings replaced.
"""
for col in [column_to_replace]:
df[col] = df[col].str.replace(original, replaced)
replace_columns(education_df, "education", "Licenciado", "Licenciatura")
replace_columns(education_df, "education", "Estudiante de licenciatura", "Licenciatura")
replace_columns(education_df, "education", "estudiante de doctorado", "Doctorado")
replace_columns(education_df, "education", "Doctorado en curso", "Doctorado")
replace_columns(education_df, "education", "Estudiante de Doctorado", "Doctorado")
replace_columns(education_df, "education", "En proceso de tesis de maestría", "Maestría")
replace_columns(education_df, "education", "Postdoctorado", "Doctorado")
We plot, creating a function for later, this time vertically.
def vertical_bar_plot(df, serie, title=None):
plt.figure(figsize=(15,10))
ax = df.groupby(serie).size().sort_values(ascending=False).plot.bar()
ax.set_title(title)
ax.set_xlabel("Researchers")
ax.set_ylabel("Frecuency")
def add_value_labels(ax, spacing=5):
for rect in ax.patches:
y_value = rect.get_height()
x_value = rect.get_x() + rect.get_width() / 2
space = spacing
va = 'bottom'
if y_value < 0:
space *= -1
va = 'top'
label = y_value
ax.annotate(
label,
(x_value, y_value),
xytext=(0, space),
textcoords="offset points",
ha='center',
va=va)
add_value_labels(ax)
plt.xticks(rotation=0)
vertical_bar_plot(education_df, "education", "Education")
We have that most respondents have or are getting a doctorate grade, followed by those that have or are getting a licentiate degree.
We create a function that allow us to: 1) remove accents and uppercases,
2) join text from all rows in serie, and
3) drop NA's in case of having.
def extract_text(serie):
serie.dropna(inplace=True)
serie = serie.apply(unidecode).str.casefold().reset_index(drop=True)
text = " ".join(text for text in serie)
return text
We create a function to plot. (We will reuse this function later.)
def make_worldcloud(data, stopwords=None):
wordcloud=WordCloud(
background_color='white',
stopwords=stopwords,
max_words=800,
max_font_size=800,
width=800, height=800,
random_state=0
).generate(data)
plt.figure(figsize = (12,15), facecolor=None)
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)
return plt.show()
We extract text from a serie and plot it.
make_worldcloud(extract_text(df["area"]))
We run again adding a list of stopwords as argument.
make_worldcloud(extract_text(df["area"]), ["psicologia", "y", "la", "de"])
We see that neuroscience, neuropsychology, social psychology ("social"), developmentental psychology ("del desarrollo"), clinical psychology ("clinica"), and health psychology ("salud"), seem to be the most frequent areas in our sample.
Let's reuse the function to create a horizontal bar plot.
horizontal_bar_plot(df["position"])
As it was done previously, we store the new values to a new dataframe. In this case, it will be called "position_df".
position_df = df[["position", "belief"]].assign(position=df["position"].str.split(";")).explode("position").reset_index(drop=True)
We plot the data.
horizontal_bar_plot(position_df["position"])
Better, but it still does not look very good.
We group the unique values in a category we will call "Other".
position_df.loc[position_df['position'].isin((position_df['position'].value_counts()[position_df['position'].value_counts() == 1]).index), 'position'] = 'Other'
We plot the data again.
horizontal_bar_plot(position_df["position"])
We see that most respondents have the rol of "Ayudante de Trabajos Prácticos", by its acronym "ATP".
Let's see the type of methodology that predominates in our sample of researchers. Directly, we plot the methodology serie from our main dataframe.
df["methodology"].value_counts().plot.pie(figsize = (10,5), autopct='%1.0f%%', fontsize=20)
Most respondents consider themselves predominantly practising a quantitative approach, being approximately a quarter those that strictly practise a qualitative methodology.
We extract statistics and, next, plot the data directly.
df["age"].describe()
sns.distplot(df['age'])
Most respondents are located in the 20-40 age group.
We directly plot the data.
df["belief"].value_counts().plot.pie(title="Do you believe that there is a crisis in science?",
figsize = (10,5),
autopct = "%1.0f%%",
fontsize = 20)
The results are almost divided. Other surveys, such as the Baker (2016) survey, perceive higher results as to "yes" percentages.
Below we will be seeing how those respondents who said "yes" justify their answers.
We group the belief in crisis by career stage (researchers' education). We plot the data directly, enlarging the plot size.
plt.figure(figsize=(15,10))
sns.countplot(x='education', hue='belief', data=education_df)
We don't observe a big difference analyzing by career stage.
We can also analyze by position in college.
plt.figure(figsize=(15,10))
sns.countplot(x='position', hue='belief', data=position_df)
In this case, ATP's seem to believe a little more in crisis in science.
sns.countplot(x="methodology", hue="belief", data=df)
Let's take a closer look.
x, y = 'methodology', "belief"
df1 = df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
height=5,
hue_order=["No", "Sí"],
aspect=2)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
Considering methodology, we can see that there are not substantial differences between usage of mixted and quantitative methodology as to belief in a crisis in science. However, there is a small difference between those that use predominatly qualitative methodology. That is, qualitative researchers seem to believe more in a crisis in science.
Likewise, it is worth noting that the results between those using predominantly quantitative methodology are divided, given that the called "replicability crisis" has a lot to do with statistical problems, such as huge confidence in p-value and null hypothesis testing, and statistical fallacies.
sns.boxplot(data=df, x='belief', y='age')
There is not a clear correlation with the variable of belief in crisis in science.
Let's go to reuse the make_worldcloud() and extract_text() functions, built previously, to analyse justifications for "yes" answers to belief in crisis.
However, the qualitative analysis will be performed more thoroughly here.
make_worldcloud(extract_text(df["belief_comments"]))
It doesn't look very good.
We add stopwords.
make_worldcloud(extract_text(df["belief_comments"]), ["que", "la", "y", "por", "porque", "en", "el", "para", "de", "se", "lo"
, "a", "como", "tambien", "los", "las", "del", "hay", "una", "pero",
"esta", "ciencia", "investigadores", "investigacion", "no", "su", "un",
"con", "al", "e", "mucha", "crisis", "o", "es", "cientifico"])
Having filtered vague words, there are some words more frequent among those that answered "yes" to the question "Do you believe there are a crisis in science?". Such words more frequent are replicability ("replicabilidad"), system ("sistema"), absence ("falta"), and quality ("calidad").
Let's see how many comments mentioned the "replicability" word as a cause of the crisis.
We create a new dataframe removing accents and uppercase of the comments.
belief_comments_df = df["belief_comments"].dropna().apply(unidecode).str.casefold().to_frame().reset_index(drop=True)
belief_comments_df["belief_comments"].count()
l = [text for text in belief_comments_df["belief_comments"]]
for (i, text) in enumerate(l):
print('Comment %d:\n'%(i+1), text)
We add the comments mentioning "replica" to a list. We use "replica" to catch both "replicacion" and "replicabilidad".
l = [text for text in belief_comments_df["belief_comments"] if "replica" in text]
We print the data formatted.
for (i, text) in enumerate(l):
print('Comment %d:\n'%(i+1), text)
Only seven comments mention "replicabilidad" or "replicación" as causes of crisis in science.
In this point, let's go to create tidy tables that allow us to plot easily. These data, given that are provided for a likert scale, will be plotted with the HH package in R. The plotting code will be available in the R Script.
First, let's create a function that builds a table from a column provided.
def make_table(column):
"""
Returns: a table.
"""
df = column.value_counts().to_frame().reset_index()
df = df.T
df.columns = df.iloc[0]
df = df.drop(df.index[0])
return df
Second, we apply the previous function to create tables iteratively from an index to other.
def tables_by_columns(index_col_1, index_col_2):
"""
Returns: a list containing different tables created from indexes.
"""
l = []
for (i, column) in enumerate(df):
if (i >= index_col_1 and i <= index_col_2):
l.append(make_table(df[column]))
return l
Third, we combinate the tables creating only one.
def combinate_tables(l):
"""
Returns: a new dataframe.
"""
df = pd.concat(l)
df.reset_index(level=0, inplace=True)
df = df.rename(columns={'index': 'Measures'})
return df
Finally, we convert numerical values to int, given that by default they are strings.
def convert_to_int(df):
"""
Returns: a df with numerical values converted to int.
"""
for (i, column) in enumerate(df):
if (i > 0):
df[[column]] = df[[column]].astype('Int64').fillna(0)
return df
We are creating three variables relative to:
1) Answers to "Value each one of the following issues concerning your opinion about science". This variable will be called "science".
2) Answers to "Mark the option that best represents your knowledge and experience with each practise in the last five years". This variable will be named "experience".
3) Answers to "Choose the option that best represents how much importance you consider that has each one of the following practises to improve quality and efficiency of research in your research area". This variable will be named "efficiency".
science = convert_to_int(combinate_tables(tables_by_columns(11, 27)))
experience = convert_to_int(combinate_tables(tables_by_columns(28, 38)))
efficiency = convert_to_int(combinate_tables(tables_by_columns(39, 49)))
Let's see the results.
science
We sort labels.
science = science[["Measures", "Nada de acuerdo", "Algo de acuerdo", "No sé", "Bastante de acuerdo", "Muy de acuerdo"]]
experience = experience[["Measures",
"Nunca lo hice, ni escuché hablar de eso",
"Nunca lo hice, pero escuché hablar de eso",
"Nunca lo hice, pero sé cómo hacerlo",
"Lo intenté, pero no lo completé",
"Sí, lo estoy haciendo",
"Sí, lo he hecho"]]
efficiency = efficiency[["Measures",
"Nada importante",
"Poco importante",
"No sé",
"Medianamente importante",
"Muy importante"]]
science
experience
efficiency
We export (to be plotted from R and the HH package).
science.to_csv(r'../data/cleaned/science.csv', index=False)
experience.to_csv(r'../data/cleaned/experience.csv', index=False)
efficiency.to_csv(r'../data/cleaned/efficiency.csv', index=False)
Now let's analyse percentage of agreement with each statement as a function of career stage and methodological approach.
def science_by_methodology(serie):
x,y = 'methodology', serie
df1 = df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
height=5,
aspect=2,
hue_order = ["Nada de acuerdo", "Algo de acuerdo", "No sé", "Bastante de acuerdo", "Muy de acuerdo"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
science_by_methodology("Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática")
science_by_methodology("Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática")
science_by_methodology("La realización de estudios de replicación es necesaria para el avance de la ciencia")
science_by_methodology("A las revistas científicas no les interesa publicar resultados que no son estadísticamente significativos")
science_by_methodology("Gran parte de los investigadores solamente publica los estudios en donde obtienen diferencias estadísticamente significativas")
science_by_methodology("El principal objetivo de las revistas científicas es publicar hallazgos novedosos")
science_by_methodology("Un resultado estadísticamente significativo es un resultado importante")
science_by_methodology("Una conclusión científica (por ejemplo, si un tratamiento es mejor que otro) debe estar basado en si el p-valor es o no es estadísticamente significativo")
science_by_methodology("Cuando leo un artículo tengo mayor confianza en la calidad del estudio si los resultados son estadísticamente significativos")
science_by_methodology("El valor de p = .001 confirma que el tamaño del efecto ha sido grande")
science_by_methodology("Las tareas de revisión y corrección de los manuscritos que llevan a cabo los revisores de las revistas garantizan de forma fiable la calidad de los resultados científicos")
science_by_methodology("El valor de p < .05 confirma que el hallazgo será útil para la comunidad científica")
science_by_methodology("La ciencia avanza más con estudios que plantean hipótesis novedosas que con estudios de replicación de otras investigaciones")
science_by_methodology("Si los resultados sobre una determinada temática son unánimes por parte de diferentes equipos de investigación entonces los estudios de replicación no son necesarios")
science_by_methodology("Creo que, en general, los errores que se pueden haber cometido en un estudio científico siempre se detectan y corrigen antes de ser publicados")
science_by_methodology("Los estudios de replicación solamente tienen sentido cuando no se detectan diferencias estadísticamente significativas en el estudio original")
science_by_methodology("No es necesario replicar un estudio cuando ya se detectaron efectos estadísticamente significativos en el estudio original")
science_by_methodology("Que un resultado no fuera estadísticamente significativo sería un criterio para no seguir investigando esas variables")
def science_by_education(serie):
x,y = 'education', serie
df1 = education_df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
#orient="h",
height=5,
aspect=2,
hue_order = ["Nada de acuerdo", "Algo de acuerdo", "No sé", "Bastante de acuerdo", "Muy de acuerdo"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
science_by_education("Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática")
science_by_education("Cuando los resultados de diferentes investigadores son contradictorios entonces sería necesario llevar a cabo un estudio de replicación sobre la misma temática")
science_by_education("La realización de estudios de replicación es necesaria para el avance de la ciencia")
science_by_education("A las revistas científicas no les interesa publicar resultados que no son estadísticamente significativos")
science_by_education("Gran parte de los investigadores solamente publica los estudios en donde obtienen diferencias estadísticamente significativas")
science_by_education("El principal objetivo de las revistas científicas es publicar hallazgos novedosos")
science_by_education("Un resultado estadísticamente significativo es un resultado importante")
science_by_education("Una conclusión científica (por ejemplo, si un tratamiento es mejor que otro) debe estar basado en si el p-valor es o no es estadísticamente significativo")
science_by_education("Cuando leo un artículo tengo mayor confianza en la calidad del estudio si los resultados son estadísticamente significativos")
science_by_education("El valor de p = .001 confirma que el tamaño del efecto ha sido grande")
science_by_education("Las tareas de revisión y corrección de los manuscritos que llevan a cabo los revisores de las revistas garantizan de forma fiable la calidad de los resultados científicos")
science_by_education("El valor de p < .05 confirma que el hallazgo será útil para la comunidad científica")
science_by_education("La ciencia avanza más con estudios que plantean hipótesis novedosas que con estudios de replicación de otras investigaciones")
science_by_education("Si los resultados sobre una determinada temática son unánimes por parte de diferentes equipos de investigación entonces los estudios de replicación no son necesarios")
science_by_education("Creo que, en general, los errores que se pueden haber cometido en un estudio científico siempre se detectan y corrigen antes de ser publicados")
science_by_education("Los estudios de replicación solamente tienen sentido cuando no se detectan diferencias estadísticamente significativas en el estudio original")
science_by_education("No es necesario replicar un estudio cuando ya se detectaron efectos estadísticamente significativos en el estudio original")
science_by_education("Que un resultado no fuera estadísticamente significativo sería un criterio para no seguir investigando esas variables")
def experience_by_methodology(serie):
x,y = 'methodology', serie
df1 = df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
height=5,
aspect=2,
hue_order = ["Nunca lo hice, ni escuché hablar de eso",
"Nunca lo hice, pero escuché hablar de eso",
"Nunca lo hice, pero sé cómo hacerlo",
"Lo intenté, pero no lo completé",
"Sí, lo estoy haciendo",
"Sí, lo he hecho"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
experience_by_methodology('Replicar un estudio previo (1)')
experience_by_methodology('Pre-registrar un estudio antes de iniciar la recolección de datos (1)')
experience_by_methodology('Poner datos recolectados a disposición mediante plataformas o repositorios públicos (1)')
experience_by_methodology('Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (1)')
experience_by_methodology('Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (1)')
experience_by_methodology('Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (1)')
experience_by_methodology('Compartir una pre-impresión (pre-print) publicándola en un repositorio público o semi-público (1)')
experience_by_methodology('Usar revisión por pares abierta (1)')
experience_by_methodology('Publicar en revistas de acceso abierto (1)')
experience_by_methodology('Adaptar un test psicométrico (1)')
experience_by_methodology('Participar en proyectos abiertos y colaborativos a gran escala (1)')
def experience_by_education(serie):
x,y = 'education', serie
df1 = education_df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
#orient="h",
height=5,
aspect=2,
hue_order = ["Nunca lo hice, ni escuché hablar de eso",
"Nunca lo hice, pero escuché hablar de eso",
"Nunca lo hice, pero sé cómo hacerlo",
"Lo intenté, pero no lo completé",
"Sí, lo estoy haciendo",
"Sí, lo he hecho"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
experience_by_education('Replicar un estudio previo (1)')
experience_by_education('Pre-registrar un estudio antes de iniciar la recolección de datos (1)')
experience_by_education('Poner datos recolectados a disposición mediante plataformas o repositorios públicos (1)')
experience_by_education('Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (1)')
experience_by_education('Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (1)')
experience_by_education('Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (1)')
experience_by_education('Compartir una pre-impresión (pre-print) publicándola en un repositorio público o semi-público (1)')
experience_by_education('Usar revisión por pares abierta (1)')
experience_by_education('Publicar en revistas de acceso abierto (1)')
experience_by_education('Adaptar un test psicométrico (1)')
experience_by_education('Participar en proyectos abiertos y colaborativos a gran escala (1)')
def efficiency_by_methodology(serie):
x,y = 'methodology', serie
df1 = df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
height=5,
aspect=2,
hue_order = ["Nada importante",
"Poco importante",
"No sé",
"Medianamente importante",
"Muy importante"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
efficiency_by_methodology('Replicar un estudio previo (2)')
efficiency_by_methodology('Pre-registrar un estudio antes de iniciar la recolección de datos (2)')
efficiency_by_methodology('Poner datos recolectados a disposición mediante plataformas o repositorios públicos (2)')
efficiency_by_methodology('Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (2)')
efficiency_by_methodology('Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (2)')
efficiency_by_methodology('Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (2)')
efficiency_by_methodology('Compartir una pre-impresión (pre-print) publicándola en un repositorio de confianza (2)')
efficiency_by_methodology('Usar revisión por partes abierta (2)')
efficiency_by_methodology('Publicar en revistas de acceso abierto (2)')
efficiency_by_methodology('Adaptar un test psicométrico (2)')
efficiency_by_methodology('Participar en proyectos abiertos y colaborativos a gran escala (2)')
def efficiency_by_education(serie):
x,y = 'education', serie
df1 = education_df.groupby(x)[y].value_counts(normalize=True)
df1 = df1.mul(100)
df1 = df1.rename('percent').reset_index()
g = sns.catplot(x=x,
y='percent',
hue=y,
kind='bar',
data=df1,
#orient="h",
height=5,
aspect=2,
hue_order = ["Nada importante",
"Poco importante",
"No sé",
"Medianamente importante",
"Muy importante"])
g.ax.set_ylim(0,100)
for ax in g.axes.ravel():
for p in ax.patches:
ax.annotate(format(p.get_height(), '.2f'), (p.get_x() + p.get_width() / 2.,
p.get_height()), ha = 'center', va = 'center', xytext = (0, 10),
textcoords = 'offset points')
g._legend.remove()
plt.legend(loc='upper right')
plt.title(serie + "\n" + "\n")
efficiency_by_education('Replicar un estudio previo (2)')
efficiency_by_education('Pre-registrar un estudio antes de iniciar la recolección de datos (2)')
efficiency_by_education('Poner datos recolectados a disposición mediante plataformas o repositorios públicos (2)')
efficiency_by_education('Compartir los métodos analíticos (e.g., scripts de análisis) en plataformas o repositorios públicos (2)')
efficiency_by_education('Poner los materiales (e.g., cuestionarios, procedimientos) a disposición mediante plataformas o repositorios públicos (2)')
efficiency_by_education('Reportar toda la información necesaria detalladamente para que otras personas puedan replicar mi estudio (2)')
efficiency_by_education('Compartir una pre-impresión (pre-print) publicándola en un repositorio de confianza (2)')
efficiency_by_education('Usar revisión por partes abierta (2)')
efficiency_by_education('Publicar en revistas de acceso abierto (2)')
efficiency_by_education('Adaptar un test psicométrico (2)')
efficiency_by_education('Participar en proyectos abiertos y colaborativos a gran escala (2)')
barriers_1_by_methodology = df[["barriers_1", "methodology"]].assign(barriers_1=df[["barriers_1"]].barriers_1.str.split(";")).explode("barriers_1").reset_index(drop=True)
barriers_1_by_education = df[["barriers_1", "education"]].assign(education=df["education"].str.split(";")).explode("education").reset_index(drop=True)
barriers_1_by_education = barriers_1_by_education[["barriers_1", "education"]].assign(barriers_1=barriers_1_by_education[["barriers_1"]].barriers_1.str.split(";")).explode("barriers_1").reset_index(drop=True)
replace_columns(barriers_1_by_education, "education", "Licenciado", "Licenciatura")
replace_columns(barriers_1_by_education, "education", "Estudiante de licenciatura", "Licenciatura")
replace_columns(barriers_1_by_education, "education", "estudiante de doctorado", "Doctorado")
replace_columns(barriers_1_by_education, "education", "Doctorado en curso", "Doctorado")
replace_columns(barriers_1_by_education, "education", "Estudiante de Doctorado", "Doctorado")
replace_columns(barriers_1_by_education, "education", "En proceso de tesis de maestría", "Maestría")
replace_columns(barriers_1_by_education, "education", "Postdoctorado", "Doctorado")
replace_columns(barriers_1_by_education, "barriers_1", "[0-9.]", "")
g = sns.catplot(y='barriers_1',
col='education',
data=barriers_1_by_education,
kind="count",
aspect=.8,
order=barriers_1_by_education["barriers_1"].value_counts().index)
for ax in g.axes.ravel():
for p in ax.patches:
percentage = '{0:g}'.format(p.get_width())
x = p.get_x() + p.get_width() + 0.02
y = p.get_y() + p.get_height()/2
ax.annotate(percentage, (x, y))
replace_columns(barriers_1_by_methodology, "barriers_1", "[0-9.]", "")
g = sns.catplot(y='barriers_1',
col='methodology',
data=barriers_1_by_methodology,
kind="count",
order=barriers_1_by_methodology["barriers_1"].value_counts().index)
for ax in g.axes.ravel():
for p in ax.patches:
percentage = '{0:g}'.format(p.get_width())
x = p.get_x() + p.get_width() + 0.02
y = p.get_y() + p.get_height()/2
ax.annotate(percentage, (x, y))
As we have already done previously, we create a new dataframe with rows extended by semi-colons.
barriers_1_df = df[["barriers_1"]].assign(barriers_1=df[["barriers_1"]].barriers_1.str.split(";")).explode("barriers_1").reset_index(drop=True)
We replace the numbers at the beginning of each row. (We reuse the replace_columns() function defined previously.)
replace_columns(barriers_1_df, "barriers_1", "[0-9.]", "")
We plot.
horizontal_bar_plot(barriers_1_df["barriers_1"], "Major barriers against adopting open science practices")
Now we plot it adding percents.
def horizontal_bar_plot_with_percents(serie, title=None):
y = serie.value_counts(ascending=True)
fig, ax = plt.subplots(figsize=(20,15))
ax.tick_params(labelsize=20)
ax.barh(y.index, y, height=0.75, color="black")
ax.set_title(title, fontsize=20)
#ax.set_xlabel("Researchers", fontsize=20)
#ax.set_ylabel("Frecuency", fontsize=20)
_, xmax = plt.xlim()
plt.xlim(0, xmax)
plt.xticks([])
for i, v in enumerate(y):
#ax.text(v + .5, i, str('{}%'.format(round(v * 100 / 90), 2)), fontsize=20, ha='left', va='center')
ax.text(v + .5, i, str(format(v * 100 / 90, '.2f')), fontsize=20, ha='left', va='center')
plt.show()
horizontal_bar_plot_with_percents(barriers_1_df["barriers_1"])
### 7) Percentage of agreement with each, and combined, statements about attitudes against adopting open science practices. Analyse as a function of career stage and methodological approach
make_worldcloud(extract_text(df["barriers_2"]), ["de", "en", "la", "que", "y", "lo", "las", "para", "el", "no",
"por", "a", "e", "los", "mi", "es", "se", "con", "cual", "veces", "muchas",
"mayor", "un"])
barriers_2_df =df["barriers_2"].dropna().apply(unidecode).str.casefold().to_frame().reset_index(drop=True)
barriers_2_df["barriers_2"].count()
l = [text for text in barriers_2_df["barriers_2"]]
for (i, text) in enumerate(l):
print('Comment %d:\n'%(i+1), text)
This qualitative analysis will be performed more thoroughly here.
In the end, let's see all comments to the "Finally, if you have any ideas or comments regarding this survey or the topic it covers, please write them briefly below" item.
l = [text for text in df["comments"].dropna()]
for (i, text) in enumerate(l):
print('Comment %d:\n'%(i+1), text)
We add the mean and standart desviation of the tables.
science["M"] = round(science.apply(lambda row: (row["Nada de acuerdo"] * 1) +
(row["Algo de acuerdo"] * 2) +
(row["No sé"] * 3) +
(row["Bastante de acuerdo"] * 4 +
row["Muy de acuerdo"] * 5)
, axis=1) / 90, 2)
efficiency["M"] = round(efficiency.apply(lambda row: (row["Nada importante"] * 1) +
(row["Poco importante"] * 2) +
(row["No sé"] * 3) +
(row["Medianamente importante"] * 4 +
row["Muy importante"] * 5)
, axis=1) / 90, 2)
experience["M"] = round(experience.apply(lambda row: (row["Nunca lo hice, ni escuché hablar de eso"] * 1) +
(row["Nunca lo hice, pero escuché hablar de eso"] * 2) +
(row["Nunca lo hice, pero sé cómo hacerlo"] * 3) +
(row["Lo intenté, pero no lo completé"] * 4 +
row["Sí, lo estoy haciendo"] * 5 +
row["Sí, lo he hecho"] * 6)
, axis=1) / 90, 2)
science["SD"] = science.apply(lambda row: (row["Nada de acuerdo"] * 1) +
(row["Algo de acuerdo"] * 4) +
(row["No sé"] * 9) +
(row["Bastante de acuerdo"] * 16 +
row["Muy de acuerdo"] * 25)
, axis=1) / 90
efficiency["SD"] = efficiency.apply(lambda row: (row["Nada importante"] * 1) +
(row["Poco importante"] * 4) +
(row["No sé"] * 9) +
(row["Medianamente importante"] * 16 +
row["Muy importante"] * 25)
, axis=1) / 90
experience["SD"] = experience.apply(lambda row: (row["Nunca lo hice, ni escuché hablar de eso"] * 1) +
(row["Nunca lo hice, pero escuché hablar de eso"] * 4) +
(row["Nunca lo hice, pero sé cómo hacerlo"] * 9) +
(row["Lo intenté, pero no lo completé"] * 16 +
row["Sí, lo estoy haciendo"] * 25 +
row["Sí, lo he hecho"] * 36)
, axis=1) / 90
science["SD"] = round(np.sqrt(science["SD"] - science["M"]), 2)
experience["SD"] = round(np.sqrt(experience["SD"] - experience["M"]), 2)
efficiency["SD"] = round(np.sqrt(efficiency["SD"] - efficiency["M"]), 2)
science
experience
efficiency
We transform the count values into percentages.
science_cols = ["Nada de acuerdo", "Algo de acuerdo", "No sé", "Bastante de acuerdo", "Muy de acuerdo"]
experience_cols = ["Nunca lo hice, ni escuché hablar de eso",
"Nunca lo hice, pero escuché hablar de eso",
"Nunca lo hice, pero sé cómo hacerlo",
"Lo intenté, pero no lo completé",
"Sí, lo estoy haciendo",
"Sí, lo he hecho"]
efficiency_cols = ["Nada importante",
"Poco importante",
"No sé",
"Medianamente importante",
"Muy importante"]
science[science_cols] = round(science[science_cols].div(science[science_cols].sum(axis=1), axis=0).multiply(100).astype("float"), 2)
experience[experience_cols] = round(experience[experience_cols].div(experience[experience_cols].sum(axis=1), axis=0).multiply(100).astype("float"), 2)
efficiency[efficiency_cols] = round(efficiency[efficiency_cols].div(efficiency[efficiency_cols].sum(axis=1), axis=0).multiply(100).astype("float"), 2)
science
experience
efficiency